﻿using Owin;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Jhong.FunMVC
{
    using O = FunMVCOption;

    internal class ThrowExceptionHandler
    {
        #region
        private readonly static string _baseHtml = @"<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>
<html xmlns='http://www.w3.org/1999/xhtml'><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
<style type='text/css'>
body { background-color: #FFFFFF; font-size: .75em; font-family: Verdana, Helvetica, Sans-Serif; margin: 0; padding: 0;	color: #696969; }
a:link { color: #000000; text-decoration: underline; }
a:visited { color: #000000; }
a:hover { color: #000000; text-decoration: none; }
a:active { color: #12eb87; }
p, ul {	margin-bottom: 20px; line-height: 1.6em; }
pre { font-size: 1.2em;	margin-left: 20px; margin-top: 0px; }
h1, h2, h3, h4, h5, h6 { font-size: 1.6em; color: #000;	font-family: Arial, Helvetica, sans-serif; }
h1 { font-weight: bold;	margin-bottom: 0; margin-top: 0; padding-bottom: 0; }
h2 { font-size: 1em; padding: 0 0 0px 0; color: #696969; font-weight: normal; margin-top: 0; margin-bottom: 20px; }
h2.exceptionMessage { white-space: pre; }
h3 { font-size: 1.2em; }
h4 { font-size: 1.1em; }
h5, h6 { font-size: 1em; }
#header { position: relative; margin-bottom: 0px; color: #000; padding: 0; background-color: #5c87b2; height: 38px; padding-left: 10px; }
#header h1 { font-weight: bold;	padding: 5px 0;	margin: 0; color: #fff;	border: none; line-height: 2em;	font-family: Arial, Helvetica, sans-serif; font-size: 32px !important; }
#header-image { float: left; padding: 3px; margin-left: 1px; margin-right: 1px; }
#header-text { color: #fff; font-size: 1.4em; line-height: 38px; font-weight: bold; }
#main {	padding: 20px 20px 15px 20px; background-color: #fff; _height: 1px; }
#footer { color: #999; padding: 5px 0; text-align: left; line-height: normal; margin: 20px 0px 0px 0px;	font-size: .9em; border-top: solid 1px #5C87B2; }
#footer-powered-by { float: right; }
.details { font-family: monospace; border: solid 1px #e8eef4; white-space: pre; font-size: 1.2em; overflow: auto; padding: 6px; margin-top: 6px; background-color: #eeeeff; color: 555555 }
.details-wrapped { white-space: normal }
.details-header { margin-top: 1.5em }
.details-header a { font-weight: bold; text-decoration: none }
p { margin-bottom: 0.3em; margin-top: 0.1em }
.sourceErrorLine { color: #770000; font-weight: bold; }
</style>
<title>{0}</title>
</head>
<body>
<div class='page'>
<div id='header'>
<div id='header-text'>Application Exception</div>
</div>
<div id='main'>
  <h1>{1}</h1>
  <h2 class='exceptionMessage'>{2}</h2>
  <p><strong>Description:</strong> {3}</p><p><strong>Details:</strong> Requested URL: {4}</p>
<div><strong>Exception stack trace:</strong></div>
<div class='details'>{5}</div><div id='footer'>
  <div id='footer-powered-by'>Powered by <a href='http://jhonge.net'>FunMVC</a></div>
</div>
</div>
</div>
</body></html>";

        private static readonly string _base = null;

        private static string GetErrorHTML(params string[] args)
        {
            var sb = new StringBuilder(1000);
            sb.Append(@"<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>
<html xmlns='http://www.w3.org/1999/xhtml'><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
<style type='text/css'>
body { background-color: #FFFFFF; font-size: .75em; font-family: Verdana, Helvetica, Sans-Serif; margin: 0; padding: 0;	color: #696969; }
a:link { color: #000000; text-decoration: underline; }
a:visited { color: #000000; }
a:hover { color: #000000; text-decoration: none; }
a:active { color: #12eb87; }
p, ul {	margin-bottom: 20px; line-height: 1.6em; }
pre { font-size: 1.2em;	margin-left: 20px; margin-top: 0px; }
h1, h2, h3, h4, h5, h6 { font-size: 1.6em; color: #000;	font-family: Arial, Helvetica, sans-serif; }
h1 { font-weight: bold;	margin-bottom: 0; margin-top: 0; padding-bottom: 0; }
h2 { font-size: 1em; padding: 0 0 0px 0; color: #696969; font-weight: normal; margin-top: 0; margin-bottom: 20px; }
h2.exceptionMessage { white-space: pre; }
h3 { font-size: 1.2em; }
h4 { font-size: 1.1em; }
h5, h6 { font-size: 1em; }
#header { position: relative; margin-bottom: 0px; color: #000; padding: 0; background-color: #5c87b2; height: 38px; padding-left: 10px; }
#header h1 { font-weight: bold;	padding: 5px 0;	margin: 0; color: #fff;	border: none; line-height: 2em;	font-family: Arial, Helvetica, sans-serif; font-size: 32px !important; }
#header-image { float: left; padding: 3px; margin-left: 1px; margin-right: 1px; }
#header-text { color: #fff; font-size: 1.4em; line-height: 38px; font-weight: bold; }
#main {	padding: 20px 20px 15px 20px; background-color: #fff; _height: 1px; }
#footer { color: #999; padding: 5px 0; text-align: left; line-height: normal; margin: 20px 0px 0px 0px;	font-size: .9em; border-top: solid 1px #5C87B2; }
#footer-powered-by { float: right; }
.details { font-family: monospace; border: solid 1px #e8eef4; white-space: pre; font-size: 1.2em; overflow: auto; padding: 6px; margin-top: 6px; background-color: #eeeeff; color: 555555 }
.details-wrapped { white-space: normal }
.details-header { margin-top: 1.5em }
.details-header a { font-weight: bold; text-decoration: none }
p { margin-bottom: 0.3em; margin-top: 0.1em }
.sourceErrorLine { color: #770000; font-weight: bold; }
</style>");
            sb.Append(string.Format("<title>{0}</title>", args[0]));
            sb.Append(@"</head>
<body>
<div class='page'>
<div id='header'>
<div id='header-text'>Application Exception</div>
</div>");
            sb.Append("<div id='main'>");
            sb.Append(string.Format("<h1>{0}</h1>", args[1]));
            sb.Append(string.Format("<h2 class='exceptionMessage'>{0}</h2>", args[2]));
            sb.Append(string.Format(@"<p><strong>Description:</strong> {0}</p><p><strong>Details:</strong> Requested URL: {1}</p>
<div><strong>Exception stack trace:</strong></div>", args[3], args[4]));
            sb.Append(string.Format("<div class='details'>{0}</div><div id='footer'>", args[5]));
            sb.Append(@"<div id='footer-powered-by'>Powered by <a href='http://jhonge.net'>FunMVC</a></div>
</div>
</div>
</div>
</body></html>");
            return sb.ToString();
        }

        #endregion


        public static void ThrowException(Request request, Response response, Exception ex, string title = "", string url = "")
        {
            var exx = ex as PageNotFoundException;
            if (null != exx)
            {
                ex = exx.Exception;
                response.HttpStatusCode = 404;
            }
            else
            {
                response.HttpStatusCode = 500;
            }
            var mode = ErrorMode.RemoteOnly;
            if (null != O.FMOption && null != O.FMOption.CustomError) mode = O.FMOption.CustomError.ErrorMode;
            switch (mode)
            {
                case ErrorMode.On:
                    if (false == ThrowCustomError(ex, response)) ThrowInternalException(request, response, ex, title, url);
                    break;
                case ErrorMode.Off:
                    ThrowInternalException(request, response, ex, title);
                    break;
                case ErrorMode.RemoteOnly:
                    if (ShouldThrow(request))
                    {
                        ThrowInternalException(request, response, ex, title);
                        break;
                    }
                    if (false == ThrowCustomError(ex, response)) ThrowInternalException(request, response, ex, title, url);
                    break;
            }
        }

        private static void ThrowInternalException(Request request, Response response, Exception ex, string title = "", string url = "")
        {
            var html = GetErrorHTML(title, ex.GetType().Name, string.Empty, ex.Message, null != request ? request.Uri.AbsolutePath : string.IsNullOrWhiteSpace(url) ? string.Empty : url, ex.StackTrace);
            response.ContentType = @"text/html;charset=utf-8";
            response.Write(html);
        }





        private static bool ShouldThrow(Request request)
        {
            if (null == request) return false;
            var ip = request.RemoteIpAddress;
            if (ip.Equals("::1") || ip.Equals("127.0.0.1") || ip.Equals("localhost"))
                return true;
            return false;
        }

        private static bool ThrowCustomError(Exception ex, Response response)
        {
            if (null == O.FMOption.CustomError) return false;
            if (ex is PageNotFoundException)
            {
                if (string.IsNullOrWhiteSpace(O.FMOption.CustomError.PageNotFoundPage)) return false;
                response.ContentType = @"text/html;charset=utf-8";
                response.Write(string.Format("<script>location.href='{0}'</script>", FunMVCOption.FMOption.CustomError.PageNotFoundPage));
                return true;
            }
            if (string.IsNullOrWhiteSpace(O.FMOption.CustomError.CustomErrorPage)) return false;
            response.ContentType = @"text/html;charset=utf-8";
            response.Write(string.Format("<script>location.href='{0}'</script>", FunMVCOption.FMOption.CustomError.CustomErrorPage));
            return true;
        }





    }
}
